package mss

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"math"
	"math/rand"
	"mss/internal/salvedev"
	"strconv"
	"time"
)

type BoostDevice struct {
	Remark    string `yaml:"remark"`
	TcpPort   uint   `yaml:"tcp_prot"`
	SalveAddr byte   `yaml:"salve_addr"`

	Values []SingleValue `yaml:"values"`

	filename string
	salvedev *salvedev.ModbusSlave
}

type SingleValue struct {
	Remark       string `yaml:"remark"`
	FunctionCode byte   `yaml:"function_code"`
	Addr         uint16 `yaml:"addr"`
	Value        string `yaml:"value"`

	// 以下字段仅在功能码3或4时有效
	Quantity   uint     `yaml:"quantity"`    //寄存器数量，1 或 2 或 4
	DataType   string   `yaml:"data_type"`   //int 整数（默认）    float 浮点数
	ChangeType string   `yaml:"change_type"` //fixed 固定值（默认）   random 一定范围内的随机值
	ValueRange []string `yaml:"value_range"` //动态值时的取值范围，闭区间。ChangeType=random时有效
}

func (d *BoostDevice) Key() string {
	return fmt.Sprintf("%d:%d", d.TcpPort, d.SalveAddr)
}

func (d *BoostDevice) UpdateValues() {
	for _, v := range d.Values {
		switch v.FunctionCode {
		case 0x01: // 线圈
			d.salvedev.SetCoil(v.Addr, v.Value == "true")
		case 0x02: // 离散输入
			d.salvedev.SetDiscreteInput(v.Addr, v.Value == "true")
		case 0x03, 0x04: // 保持寄存器
			if v.Quantity == 0 {
				v.Quantity = 1
			}

			buf := make([]byte, 2*v.Quantity)
			var uintV uint64

			if v.ChangeType == "random" {
				if len(v.ValueRange) != 2 {
					continue
				}

				switch v.DataType {
				case "float":
					f1, _ := strconv.ParseFloat(v.ValueRange[0], 64)
					f2, _ := strconv.ParseFloat(v.ValueRange[1], 64)
					uintV = math.Float64bits(randFloat64(f1, f2))
				default:
					v1, _ := strconv.ParseUint(v.ValueRange[0], 10, 64)
					v2, _ := strconv.ParseUint(v.ValueRange[1], 10, 64)
					uintV = uint64(randInt(int(v1), int(v2)))
				}
			} else {
				switch v.DataType {
				case "float":
					fv, err := strconv.ParseFloat(v.Value, 64)
					if err != nil {
						continue
					}
					switch v.Quantity {
					case 1:
						continue
					case 2:
						uintV = uint64(math.Float32bits(float32(fv)))
					case 4:
						uintV = math.Float64bits(fv)
					}
				default:
					iv, err := strconv.ParseUint(v.Value, 10, 64)
					if err != nil {
						continue
					}
					uintV = iv
				}
			}

			switch v.Quantity {
			case 1:
				binary.BigEndian.PutUint16(buf, uint16(uintV))
			case 2:
				binary.BigEndian.PutUint32(buf, uint32(uintV))
			case 4:
				binary.BigEndian.PutUint64(buf, uintV)
			}

			uint16s := make([]uint16, len(buf)/2)
			binary.Read(bytes.NewReader(buf), binary.BigEndian, &uint16s)

			if v.FunctionCode == 0x03 {
				d.salvedev.SetHoldingRegisters(v.Addr, uint16s)
			} else if v.FunctionCode == 0x04 {
				d.salvedev.SetInputRegisters(v.Addr, uint16s)
			}
		}
	}
}

// 生成 [min, max) 范围内的随机 float64
func randFloat64(min, max float64) float64 {
	src := rand.NewSource(time.Now().UnixNano())
	rng := rand.New(src)
	return min + rng.Float64()*(max-min)
}

// 生成 [min, max] 范围内的随机 int
func randInt(min, max int) int {
	if min >= max {
		return min
	}
	// 创建独立的随机生成器
	src := rand.NewSource(time.Now().UnixNano())
	rng := rand.New(src)
	return min + rng.Intn(max-min+1) // Intn(n) 生成 [0, n) 的整数
}
